home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume12 / cnews / part09 < prev    next >
Encoding:
Internet Message Format  |  1987-10-21  |  46.6 KB

  1. Subject:  v12i034:  C News alpha release, Part09/14
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rs@uunet.UU.NET
  5.  
  6. Submitted-by: utzoo!henry (Henry Spencer)
  7. Posting-number: Volume 12, Issue 34
  8. Archive-name: cnews/part09
  9.  
  10.  
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 9 (of 14)."
  19. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  20. if test -f 'newsbin.proto/maint/arbitron' -a "${1}" != "-c" ; then 
  21.   echo shar: Will not clobber existing file \"'newsbin.proto/maint/arbitron'\"
  22. else
  23. echo shar: Extracting \"'newsbin.proto/maint/arbitron'\" \(7860 characters\)
  24. sed "s/^X//" >'newsbin.proto/maint/arbitron' <<'END_OF_FILE'
  25. X#! /bin/sh
  26. X# @(#)arbitron    2.4.2    06/05/87
  27. X# arbitron -- this program produces rating sweeps for USENET.
  28. X#
  29. X# Usage: arbitron
  30. X#
  31. X# To use this program, edit the "configuration" section below so that the
  32. X# information is correct for your site, and then run it. It will produce a
  33. X# readership survey for your machine and mail that survey to decwrl, with
  34. X# a cc to you.
  35. X#
  36. X# To participate in the international monthly ratings sweeps, 
  37. X# run "arbitron" every month. I will run the statistics program on the last
  38. X# day of each month; it will include any report that has reached it by that
  39. X# time. To make sure your site's data is included, run the survey program no
  40. X# later than the 20th day of each month.
  41. X#
  42. X# Brian Reid, DEC Western Research Lab, reid@decwrl
  43. X# Updated and bugfixed by 
  44. X#    Spencer Thomas, U.of Utah
  45. X#    Geoff Kuenning, SAH Consulting
  46. X# Updated to work with 2.10.1 and older news systems by
  47. X#    Lindsay Cleveland, AT&T Technologies/Bell Labs
  48. X# Made to work with 16-bit address spaces by
  49. X#    Andy Walker, Maths Dept., University of Nottingham, UK
  50. X# Nagging Bourne shell bug fixed by
  51. X#    Tom Donahue, Rabbit Software Corp
  52. X#
  53. X# Note that the results of this program are dependent on the rate at which
  54. X# you expire news.  If you are a small site that expires news rapidly, the
  55. X# results may indicate fewer active readers than you actually have.
  56. X#
  57. X###########################################################################
  58. X# Configuration information. Edit this section to reflect your site data. #
  59. XTMPDIR=/tmp
  60. XNEWS=/usr/lib/news
  61. XSPOOL=/usr/spool/news
  62. X
  63. X# Make a crude stab at determining the system type. If your installation has
  64. X# only one type of system, you can edit out the "if" statement and just turn
  65. X# this into an assignment statement of the correct value.
  66. Xif [ -d /usr/ucb ]
  67. Xthen
  68. X    STYPE="bsd"
  69. Xelse
  70. X    STYPE="usg"
  71. Xfi
  72. X
  73. X# Range of /etc/passwd UID's that represent actual people (rather than
  74. X# maintenance accounts or daemons or whatever)
  75. XlowUID=5
  76. XhighUID=9999
  77. X
  78. X# If you aren't running a distributed news system (nntpd & rrn, usually),
  79. X# leave NEWSHOST blank. Else set it to the name of the host from which you
  80. X# can rcp a copy of the active file.
  81. XNEWSHOST=
  82. X
  83. X# uucp path: {ihnp4, decvax, ucbvax}!decwrl!netsurvey
  84. Xsummarypath="netsurvey@decwrl.dec.com $USER"
  85. X#summarypath="ihnp4!decwrl!netsurvey $USER"
  86. X
  87. X# We need to find the uucp name of your host. If this code doesn't work,
  88. X# then just put it in literally like this:
  89. X#    hostname="ihnp4"
  90. X
  91. Xcase $STYPE in
  92. X    bsd) cmd='hostname || uuname -l';;
  93. X    sysv)cmd='uname -n || uuname -l || hostname';;
  94. X    *)   cmd='uuname -l';;
  95. Xesac;
  96. X
  97. Xhostname=`sh -c "$cmd" 2>&-`
  98. X
  99. XPATH=$NEWS:/usr/ucb:/usr/bin:/bin
  100. X############################################################################
  101. Xexport PATH
  102. X# ---------------------------------------------------------------------------
  103. Xtrap "rm -f $TMPDIR/arb.*.$$; exit" 0 1 2 3 15
  104. Xset `date`
  105. Xdat="$2$6"
  106. Xdestination="${MAILER-mail} $summarypath"
  107. X
  108. X################################
  109. X# Here are several expressions, each of which figures out approximately how
  110. X# many people use this machine. Comment out all but 1 of them; pick the one
  111. X# you like best. Initially the most universal but least reliable of them is
  112. X# uncommented.
  113. X# # ###### Scheme #1: fast but usually returns too big a number
  114. Xnusers=`awk -F: "BEGIN {N=0}\\$3>=$lowUID && \\$3<=$highUID{N=N+1}END{print N}" </etc/passwd`
  115. X
  116. X# # ###### Scheme #2 (works with BSD systems)
  117. X#nusers=`last | sort -u +0 -1 | wc -l`
  118. X
  119. X# # ###### Scheme #3 (works with USG systems)
  120. X#nusers=`who /etc/wtmp | sort -u +0 -1 | wc -l`
  121. X
  122. X################################
  123. X#
  124. X# Set up awk scripts;  these are too large to pass as arguments on most
  125. X# systems.
  126. X#
  127. X# This awk script generates the actual output report.
  128. X# We use 'sed' to substitute in the shell variables to save ourselves
  129. X# endless hassle trying to find quoting/backslashing problems.
  130. X#
  131. X# The input to this script consists of two types of lines (pre-sorted):
  132. X#
  133. X#    (1) Active-file lines.  These have four fields:  newsgroup name,
  134. X#        first existing article, last article number, 'y' or 'n'
  135. X#        to allow/disallow posting.
  136. X#            mod.mac 00001 00001 y
  137. X#
  138. X#    (2) .newsrc-derived lines.  These have three fields:  the newsgroup
  139. X#        name, the user name and the articles-read information.  The latter
  140. X#        can be arbitrarily complex.  It can also be arbitrarily long;
  141. X#        this can potentially break either awk or sed, in which
  142. X#        case the script will not work.
  143. X#            mod.map joe 1-199
  144. X#
  145. X#    The script uses the type 1 lines to define the newsgroups
  146. X#    and their active article ranges.  The .newsrc (type 2) lines are
  147. X#    then used to deduce which users are reading that group (a group
  148. X#    is being read if the last article seen is in that group's active
  149. X#    article range).
  150. X#
  151. Xsed "/^#/d
  152. X     s/NUSERS/$nusers/g
  153. X     s/HOSTNAME/$hostname/g
  154. X     s/DATE/$dat/g" > $TMPDIR/arb.fmt.$$ << 'DOG'
  155. X# makereport -- utility for "arbitron". Early versions were copied from a
  156. X# similar script distributed with "subscribers.sh" by Blonder, McCreery, and
  157. X# Herron.
  158. X#
  159. X    BEGIN    { rdrcount = 0 ; reader = "" ; grpcount = 0 ; realusers = 0}
  160. X#
  161. X# Active file line:  dispose of previous group (if any), record group, and
  162. X# record first and last article numbers.  Set group's reader count to none.
  163. X    NF == 4 { if (grpname != "") {
  164. X            printf("%d %s\n",grpcount, grpname)
  165. X          }
  166. X          grpname = $1
  167. X          grpfirst = $3
  168. X          grplast = $2
  169. X          grpcount = 0
  170. X        }
  171. X#
  172. X# .newsrc line.  Break out the final number, which is the last article that
  173. X# has actually been read.  This is a pretty good indicator of the person's
  174. X# true interest in the group.  If 'lastread' for the group is a current
  175. X# (unexpired) article, record a reader for that group.  Finally, record
  176. X# the user as a "real" user of the news system.
  177. X#
  178. X    NF == 3 { if ($1 != grpname) next;
  179. X          n1 = split($3, n2, "-")
  180. X          n3 = split(n2[n1], n4, ",")
  181. X          lastread = n4[n3]
  182. X    if ((grpfirst != grplast) && (lastread >= grpfirst) && (lastread <= grplast)) {
  183. X            grpcount++
  184. X            if (realuser[$2] != 1) {
  185. X                realuser[$2] = 1
  186. X                realusers++
  187. X            }
  188. X          }
  189. X        }
  190. X#
  191. X# End of file.  Print the report in 2 columns.
  192. X    END    { printf("9999 Host\t\t%s\n","HOSTNAME")
  193. X          printf("9998 Users\t\t%d\n",NUSERS)
  194. X          printf("9997 NetReaders\t%d\n",realusers)
  195. X          printf("9996 ReportDate\t%s\n","DATE")
  196. X          printf("9995 SystemType\tnews-arbitron-2.4\n")
  197. X# For reorganized network, report a group even if nobody reads it. This will
  198. X# help us keep track of where the groups propagate.
  199. X          printf("%d %s\n",grpcount, grpname)
  200. X        }
  201. XDOG
  202. X
  203. Xcat >$TMPDIR/arb.pwd.$$ <<'MOUSE'
  204. XBEGIN    { seen["/"]=1; seen[""] = 1; }
  205. X    { if (seen[$6]!=1) {
  206. X        printf("if [ -r %s/.newsrc ] ; then ", $6)
  207. X        printf("sed -n '/: [0-9]/s/:/ %s/p' <%s/.newsrc; fi\n",$1,$6)
  208. X        seen[$6]=1;
  209. X      }
  210. X}
  211. XMOUSE
  212. X
  213. X# First, make sure we have an active file
  214. Xif [ -z "$NEWSHOST" ]
  215. Xthen ACTIVE=$NEWS/active
  216. Xelse ACTIVE=/tmp/arb.active.$$
  217. X     rcp $NEWSHOST:$NEWS/active $ACTIVE
  218. Xfi
  219. X
  220. Xif [ ! -s $ACTIVE ]
  221. Xthen
  222. X    echo arbitron: ACTIVE file missing or empty. Cannot continue.
  223. X    exit 1
  224. Xfi
  225. X
  226. X# Next, get the list of .newsrc files with duplicates and unreadable files
  227. X# removed.
  228. Xawk -F: -f $TMPDIR/arb.pwd.$$ </etc/passwd | sh >$TMPDIR/arb.tmp.$$
  229. X
  230. X# Check to make sure that we found some
  231. Xif [ -s $TMPDIR/arb.tmp.$$ ]
  232. Xthen # See if "active" file has 4 fields or only two (pre-2.10.2)
  233. X     set `sed 1q < $ACTIVE`
  234. X     if [ $# -eq 2 ]
  235. X     then egrep  '^[a-z]*\.' $ACTIVE |
  236. X      while read group last
  237. X      do dir=`echo "$group" | sed 's;\.;/;g'`
  238. X         first=`ls $SPOOL/$dir | grep '^[0-9]*' | sort -n | sed 1q`
  239. X         case $STYPE in
  240. X        usg) echo "$group $last ${first:-$last} X";;
  241. X          *) echo "$group $last ${first-$last} X"
  242. X         esac
  243. X      done
  244. X     else egrep '^[a-z]*\.' $ACTIVE
  245. X     fi |
  246. X     sort - $TMPDIR/arb.tmp.$$ |
  247. X     awk -f $TMPDIR/arb.fmt.$$ |
  248. X     sort -nr |
  249. X     sed '/^$/d
  250. X      s/^999[0-9] //' |
  251. X     $destination
  252. Xelse echo Unable to find any readable .newsrc files 2>&1
  253. X     exit 1
  254. Xfi
  255. END_OF_FILE
  256. if test 7860 -ne `wc -c <'newsbin.proto/maint/arbitron'`; then
  257.     echo shar: \"'newsbin.proto/maint/arbitron'\" unpacked with wrong size!
  258. fi
  259. # end of 'newsbin.proto/maint/arbitron'
  260. fi
  261. if test -f 'rna/man/readnews.1' -a "${1}" != "-c" ; then 
  262.   echo shar: Will not clobber existing file \"'rna/man/readnews.1'\"
  263. else
  264. echo shar: Extracting \"'rna/man/readnews.1'\" \(7338 characters\)
  265. sed "s/^X//" >'rna/man/readnews.1' <<'END_OF_FILE'
  266. X.TH READNEWS 1
  267. X.SH NAME
  268. Xnews, readnews \- read news articles
  269. X.SH SYNOPSIS
  270. X.B readnews
  271. X.RB [ -n
  272. Xnewsgroups]
  273. X.RB [ -i ]
  274. X.RB [ -clpC ]
  275. X.RB [ -s [ -+?
  276. X.RI [ group ]]]
  277. X.RB [ -u
  278. Xmessageid]
  279. X.SH DESCRIPTION
  280. X.I Readnews
  281. Xwithout arguments enters command mode,
  282. Xwhich allows printing of unread articles.
  283. XThis is the normal way of using
  284. X.IR readnews .
  285. X.P
  286. X.I Readnews
  287. Xmaintains a
  288. X.I .newsrc
  289. Xfile in the user's home directory that specifies
  290. Xall news articles already read.
  291. XIt is updated at the end of each reading session.
  292. X.P
  293. XSome useful functions are available which don't use command mode.
  294. XThe flags for these are:
  295. X.TP
  296. X.B -c
  297. XCheck if there is news, and if so print `You have news.'.
  298. XA line `readnews -c' is usually placed in the system
  299. X.I .profile
  300. X.RB (  /etc/profile ).
  301. X.TP
  302. X.B -C
  303. XCheck if there is news, and print the groups and number of
  304. Xarticles in each group to be read.
  305. X.TP
  306. X.B -l
  307. XList the titles of available news articles.
  308. X.TP
  309. X.B -p
  310. XPrint all articles on standard output,
  311. Xand update
  312. X.IR newsrc .
  313. X.TP
  314. X.B -s
  315. XPrint the newsgroup subscription list.
  316. X.TP
  317. X.BI -s+ " group"
  318. XAdd
  319. X.I group
  320. Xto the subscription list.
  321. X.TP
  322. X.BI -s- " group"
  323. XSubtract
  324. X.I group
  325. Xfrom the subscription list.
  326. X.TP
  327. X.B -s?
  328. XList currently active newsgroups.
  329. X.P
  330. XThe remaining flags determine article selection,
  331. Xand may also appear in the
  332. X.I .newsrc
  333. Xfile.
  334. XOptions may be specified in the
  335. X.I .newsrc
  336. Xfile by entering lines prefixed with the word `options',
  337. Xfollowed by the options arguments.
  338. XThis is most useful with the
  339. X.B -n
  340. Xflag, specifying the usual groups one wishes to subscribe to.
  341. X.TP
  342. X\fB-n \fInewsgroups\fR
  343. XSelect all articles belonging to
  344. X.IR newsgroups .
  345. X.I newsgroups
  346. Xis a comma separated list of newsgroup names.
  347. XThe character `!' may be used to exclude certain groups,
  348. Xand the word `all' can be used to match any group.
  349. Xe.g. `-n all,!net.jokes'
  350. X.TP
  351. X.B -i
  352. XIgnore
  353. X.I .newsrc
  354. Xfile. It is not read or updated.
  355. XThis allows selection of articles that have already been read.
  356. X.TP
  357. X\fB-u \fImessageid\fR
  358. XUnsubscribe to followup articles referring to
  359. X.IR messageid .
  360. X(This flag is usually only placed in the
  361. X.I .newsrc
  362. Xfile as a result of the `u' command.)
  363. X.SH COMMANDS
  364. XThis section details the commands available when
  365. X.I readnews
  366. Xis in command mode (no
  367. X.B -clpsC
  368. Xarguments).
  369. XThe simplest way of using this mode, is to enter RETURN after every
  370. Xprompt.
  371. XThis will present to the user, a short heading for an article, then a prompt.
  372. XTyping RETURN again will print the article body.
  373. XTyping RETURN yet again will print the next heading, and so on.
  374. XIf having read the heading, you don't wish to read the article, you may
  375. Xtype `n' (or `+' or ';') which will take you directly to the next heading.
  376. X.P
  377. X.P
  378. XAn article is treated as having been read, if either you have seen
  379. Xthe article body, or typed `n' to skip over it.
  380. X.P
  381. XA number of commands operate on the `current' article.
  382. XThis is defined as the article whose header you have most recently seen.
  383. X.P
  384. XThe commands to read news are:
  385. X.TP
  386. X.B RETURN
  387. XEither print the current article,
  388. Xor go to the next article and print its header.
  389. X.TP
  390. X\fBn\fR or \fB+\fR or \fB;\fR
  391. XGo to the next article and print its header.
  392. X.TP
  393. X.B .
  394. XPrint the current article.
  395. X.TP
  396. X.B -
  397. XGo back to the previous article. This is a toggle, typing it
  398. Xtwice returns you to the original article.
  399. X.TP
  400. X.I number
  401. XGo to the article
  402. X.I number
  403. Xin the current newsgroup.
  404. XLike the `-' command,
  405. Xyou always return to the original article
  406. Xafter reading the selected article.
  407. X.TP
  408. X\fBs \fR[\fIfile\fR]
  409. XSave the current article, either in the specified file, or
  410. Xin
  411. X.BR $HOME/articles .
  412. X.TP
  413. X.B h
  414. XPrint the current header (slightly more verbose than normal header).
  415. X.TP
  416. X.B H
  417. XPrint the current header in full (very verbose).
  418. X.TP
  419. X\fBN \fR[\fInewsgroup\fR]
  420. XGo to the next newsgroup, or to the specified newsgroup.
  421. X.TP
  422. X.B u
  423. XUnsubscribe from all further followup articles on this topic.
  424. X.TP
  425. X.B U
  426. XUnsubscribe from this newsgroup, and go to the next newsgroup.
  427. X.TP
  428. X\fB!\fIcommand\fB
  429. XShell escape.
  430. X.I Command
  431. Xis executed.
  432. XIf 
  433. X.I command
  434. Xis `!'
  435. Xthe last escape command is executed.
  436. X.TP
  437. X\fBq\fR or \fBEOT\fR
  438. XQuit.
  439. XThe
  440. X.I .newsrc
  441. Xfile will be updated provided the flag
  442. X.B -i
  443. Xwas not specified.
  444. X.TP
  445. X.B x
  446. XExit.
  447. X.I .newsrc
  448. Xis left unchanged (as if no articles had been read).
  449. X.TP
  450. X.B DEL
  451. XAn interrupt will cause
  452. X.I readnews
  453. Xto terminate its current activity and return to command mode.
  454. XAn interrupt in command mode will cause `Interrupt' to be printed,
  455. Xand a subsequent interrupt will cause immediate exit (as in the `x' command).
  456. X.P
  457. XSome commands are available to send/reply or cancel news articles:
  458. X.TP
  459. X.B c
  460. XCancel article. Only the author, or news administrator can do this.
  461. X.IR postnews (1)
  462. Xis called to do the actual cancelling.
  463. X.TP
  464. X.B r
  465. XReply to sender of the current article by mail.
  466. X.I Readnews
  467. Xsets up the appropriate headers, and then calls
  468. X.IR mail (1)
  469. Xto send a reply to the sender.
  470. X.TP
  471. X.B f
  472. XPost a followup to the current article.
  473. X.I Readnews
  474. Xsets up the appropriate headers, and then calls
  475. X.IR postnews (1)
  476. Xto post the followup article.
  477. X.TP
  478. X.B p
  479. XPost an article on a new topic.
  480. X.IR postnews (1)
  481. Xis called to post the new article.
  482. X.TP
  483. X\fBm \fIperson\fB
  484. XMail to
  485. X.IR person .
  486. X.P
  487. XWhen replying by mail, or posting an article, the user
  488. Xis prompted for certain headers, and then the text of the article or mail
  489. Xitem is entered until a `.' or EOT is entered alone on a line.
  490. XThen the article/mail is posted/mailed.
  491. XOther commands are available:
  492. X.TP
  493. X\&\fB.e\fR
  494. XEdit the message/article collected so far (see
  495. X.IR ed (1)).
  496. XThe 'To:' or 'cc:' fields may be changed if mailing.
  497. XAfter editing further lines may be appended to the message.
  498. X.TP
  499. X\&\fB.i\fR
  500. XInterpolate
  501. Xthe current news article onto the end of the message.
  502. XThe interpolated item
  503. Xis indented by four spaces.
  504. X.TP
  505. X\&\fB.!\fIcmd\fR or \fB!\fIcmd\fR
  506. XShell escape.
  507. X.IR Cmd
  508. Xis executed.
  509. X.TP
  510. X.B DEL
  511. XCauses posting/mailing to be aborted, and the article entered so far
  512. Xis saved in
  513. X.B $HOME/dead.article
  514. Xor
  515. X.BR $HOME/dead.letter .
  516. X.P
  517. XIn order to permanently resubscribe to a newsgroup denied by `U',
  518. Xor a series of followups denied by `u' it is necessary to understand
  519. Xthe format of the
  520. X.I .newsrc
  521. Xfile.
  522. XThe
  523. X.I .newsrc
  524. Xfile consists of two types of lines:
  525. X.TP
  526. Xoption lines
  527. XThese start with the word `option' and contain the same arguments
  528. Xas the
  529. X.I readnews
  530. Xcommand on the command line.
  531. XFollowups are denied with `option -u <messageid>'.
  532. XTo resubscribe to further followups, the correct options line must be deleted.
  533. X.TP
  534. Xread newsgroup lines
  535. XThese have the format <newsgroup>`:' <number>, where
  536. X<number> represents the last item number seen in that particular newsgroup.
  537. XIf the newsgroup has been unsubscribed, the `:' is replaced by a `!'.
  538. XTo resubscribe the `!' must be changed back to a `:'.
  539. X.SH FILES
  540. X.ta 24
  541. X.nf
  542. X$HOME/.newsrc    options and list of previously read articles
  543. X%news    where the articles are kept
  544. X/usr/lib/news/active    current newsgroups
  545. X/usr/lib/news/help    help file
  546. X.fi
  547. X.SH SEE ALSO
  548. Xpostnews(1), mail(1), ed(1), uusend(8), uurec(8).
  549. X.SH BUGS
  550. X.I Readnews
  551. Xwith the
  552. X.B -c
  553. Xflag may say "You have news.", when the available article is a unsubscribed
  554. Xfollowup article.
  555. X.P
  556. XYou may see followups, even if you have used the `u' command.
  557. XThis is because many sites have faulty news programs, which do
  558. Xnot follow the correct protocol, or the sender did not use the `r' command.
  559. X.SH AUTHOR
  560. XMichael Rourke, University of N.S.W (decvax!mulga!michaelr:elecvax)
  561. END_OF_FILE
  562. if test 7338 -ne `wc -c <'rna/man/readnews.1'`; then
  563.     echo shar: \"'rna/man/readnews.1'\" unpacked with wrong size!
  564. fi
  565. # end of 'rna/man/readnews.1'
  566. fi
  567. if test -f 'rna/newsrc.c' -a "${1}" != "-c" ; then 
  568.   echo shar: Will not clobber existing file \"'rna/newsrc.c'\"
  569. else
  570. echo shar: Extracting \"'rna/newsrc.c'\" \(6581 characters\)
  571. sed "s/^X//" >'rna/newsrc.c' <<'END_OF_FILE'
  572. X/*
  573. X * newsrc file handling
  574. X */
  575. X
  576. X#include "defs.h"
  577. X
  578. Xstatic char nrcname[]     = NEWSRC;
  579. X
  580. Xstatic char *rcname;        /* full pathname of .newsrc */
  581. Xnewsrc *rc;            /* internal .newsrc */
  582. Xchar *rcgrps;            /* subscription from .newsrc */
  583. Xstatic newsrc *lastrc;        /* last newsrc struct in list */
  584. Xstatic int rclineno;        /* current lineno in .newsrc */
  585. Xstatic bool sortrc;        /* if we should sort on output */
  586. X
  587. Xstatic newsrc *findnewsrc();
  588. X
  589. Xreadnewsrc()
  590. X{
  591. X    register FILE *f;
  592. X    static char option[] = "options";
  593. X    char word[BUFSIZ], rest[BUFSIZ];
  594. X    extern char *getenv();
  595. X
  596. X    if ((rcname = getenv("HOME")) == NULL)
  597. X        error("No $HOME in environment.");
  598. X    rcname = newstr3(rcname, "/", nrcname);
  599. X    if ((f = fopen(rcname, "r")) == NULL)
  600. X        return;
  601. X
  602. X    rclineno = 0;
  603. X    while (getline(f, word, rest))
  604. X        if (CMP(word, option) == 0)
  605. X            dooptions(rest);
  606. X        else
  607. X            dorcline(word, rest);
  608. X    (void) fclose(f);
  609. X}
  610. X
  611. X/*
  612. X * Read a line from f, put first word into w and the rest into r.
  613. X * Discard trailing newline instead of storing it.
  614. X * This is a poor design, as w & r are unchecked for overrun.
  615. X */
  616. Xstatic
  617. Xgetline(f, w, r)
  618. Xregister FILE *f;
  619. Xchar *w, *r;
  620. X{
  621. X    register int c;
  622. X    register char *s;
  623. X
  624. X    rclineno++;
  625. X    s = w;
  626. X    while ((c = getc(f)) != EOF && c != ' ' && c != '\t')
  627. X        *s++ = c;            /* stash first word */
  628. X    *s = '\0';
  629. X
  630. X    if (c != EOF) {
  631. X        s = r;
  632. X        while ((c = getc(f)) != EOF && c != '\n')
  633. X            *s++ = c;        /* stash the rest */
  634. X        *s = '\0';
  635. X    }
  636. X
  637. X    if (c != '\n' && c != EOF)
  638. X        error("Bad format: %s line %d: %s", rcname, rclineno, w);
  639. X
  640. X    return c != EOF;
  641. X}
  642. X
  643. X/*
  644. X * Parse s into words and simulate command line arguments with them.
  645. X */
  646. Xstatic
  647. Xdooptions(s)
  648. Xchar *s;
  649. X{
  650. X    register char *cp;
  651. X    register int argc;
  652. X    register char **argv;
  653. X
  654. X    cp = s;
  655. X    while (isspace(*cp))
  656. X        cp++;
  657. X    if (!*cp)
  658. X        return;
  659. X
  660. X    argc = 1;
  661. X    argv = (char **) myalloc(sizeof(char *));
  662. X    argv[argc - 1] = cp;
  663. X    while (*cp && (cp = strpbrk(cp, " \t")) != NULL) {
  664. X        while (*cp == ' ' || *cp == '\t')
  665. X            *cp++ = '\0';
  666. X        if (*cp) {
  667. X            argc++;
  668. X            argv = (char **) myrealloc((char *) argv,
  669. X                argc * (int)sizeof(char *));
  670. X            argv[argc - 1] = cp;
  671. X        }
  672. X    }
  673. X    if (options(argc, argv, false))
  674. X        error("Bad options: %s line %d: %s", rcname, rclineno, s);
  675. X    free((char *) argv);
  676. X}
  677. X
  678. X/*
  679. X * Parse w & r together as a .newsrc newsgroup line.
  680. X */
  681. Xstatic
  682. Xdorcline(w, r)
  683. Xchar *w, *r;
  684. X{
  685. X    register char lastw;
  686. X    register int len;
  687. X    register newsrc    *np;
  688. X
  689. X    len = strlen(w);
  690. X    lastw = w[len - 1];            /* save presumed colon or bang */
  691. X    w[len - 1] = '\0';            /* nuke presumed colon */
  692. X    while (*r == ' ' || *r == '\t')
  693. X        r++;                /* skip extra whitespace */
  694. X
  695. X    /* kludges, hacks, etc. for compatibility with other readers */
  696. X    if (strncmp(r, "1-", sizeof "1-"-1) == 0)
  697. X        r += sizeof "1-"-1;        /* skip usual `1-' */
  698. X    if (*r == '\0')                /* rn's: `news.trash: ' */
  699. X        r = "0";            /* fake a zero */
  700. X
  701. X    if (lastw != ':' && lastw != NEGCHAR || !isdigit(*r))
  702. X        error("Bad line: %s line %d: %s", rcname, rclineno, w);
  703. X
  704. X    np = NEW(newsrc);
  705. X    np->n_subscribe = (bool) (lastw == ':');    /* colon or bang? */
  706. X    np->n_next = NIL(newsrc);
  707. X    np->n_last = atoi(r);            /* stash first number only */
  708. X    np->n_name = newstr(w);            /* stash n.g. name */
  709. X
  710. X    if (rc == 0)
  711. X        rc = np;
  712. X    else
  713. X        lastrc->n_next = np;
  714. X    lastrc = np;
  715. X}
  716. X
  717. X/*
  718. X * for every group in active list, which belongs to the specified subscription
  719. X * list, and has messages to be read, call func
  720. X * if no mention in newsrc file, make new entry
  721. X */
  722. Xapply(alist, group, func, dolast)
  723. Xactive *alist;
  724. Xchar *group;
  725. Xapplycom (*func)();
  726. Xbool dolast;
  727. X{
  728. X    register active *ap;
  729. X    register newsrc *np;
  730. X    register applycom act;
  731. X    register bool donesome;
  732. X
  733. X    donesome = false;
  734. X    do {
  735. X        act = stop;
  736. X        for (ap = alist; ap; ap = ap->a_next) {
  737. X            if (ap->a_seq == 0 || ap->a_low > ap->a_seq)
  738. X                continue;    /* empty group */
  739. X            if (!ngmatch(ap->a_name, group))
  740. X                continue;
  741. X            if ((np = findnewsrc(ap->a_name)) == NIL(newsrc)) {
  742. X                np = NEW(newsrc);
  743. X                np->n_name = newstr(ap->a_name);
  744. X                np->n_next = NIL(newsrc);
  745. X                np->n_last = 0;
  746. X                np->n_subscribe = true;
  747. X                if (!rc)
  748. X                    rc = np;
  749. X                else
  750. X                    lastrc->n_next = np;
  751. X                lastrc = np;
  752. X            }
  753. X            if (!np->n_subscribe)
  754. X                continue;
  755. X            /*
  756. X             * if we haven't read any news for a while (or at all),
  757. X             * or somehow seq got smaller (active corrupted?),
  758. X             * set last read to oldest available article
  759. X             */
  760. X            if (ap->a_low - 1 > np->n_last || ap->a_seq < np->n_last)
  761. X                np->n_last = ap->a_low - 1;
  762. X            while (np->n_last < ap->a_seq) {
  763. X                donesome = true;
  764. X                switch (act = (*func)(ap, np, false, false)) {
  765. X                case stop:        
  766. X                    return;
  767. X                case next:        
  768. X                    continue;
  769. X                case nextgroup:        
  770. X                    break;
  771. X                case searchgroup:    
  772. X                    break;
  773. X                }
  774. X                break;
  775. X            }                /* while */
  776. X            if (act == searchgroup)
  777. X                break;
  778. X        }                    /* for */
  779. X        if (act != searchgroup && dolast && donesome)
  780. X            act = (*func)(NIL(active), NIL(newsrc), true, false);
  781. X    } while (act == searchgroup);
  782. X}
  783. X
  784. X/*
  785. X * find if a newrc entry exists,
  786. X * taking advantange of the fact that requests should be
  787. X * in the same order
  788. X *
  789. X * detect when the newsrc gets out of order
  790. X * so it can be sorted at the end of the session
  791. X */
  792. Xstatic newsrc *
  793. Xfindnewsrc(name)
  794. Xregister char *name;
  795. X{
  796. X    register newsrc *np, *start;
  797. X    register bool found;
  798. X    static newsrc *nextp;
  799. X
  800. X    if (!rc)
  801. X        return NIL(newsrc);
  802. X
  803. X    found = false;
  804. X    np = nextp ? nextp : rc;
  805. X    nextp = start = np;
  806. X    do {
  807. X        if (CMP(np->n_name, name) == 0) {
  808. X            found = true;
  809. X            break;
  810. X        }
  811. X        np = np->n_next;
  812. X        if (!np)
  813. X            np = rc;
  814. X    } while (np != nextp);
  815. X
  816. X    if (!found)
  817. X        return NIL(newsrc);
  818. X    nextp = np->n_next;
  819. X    if (np != start)
  820. X        sortrc = true;
  821. X    return np;
  822. X}
  823. X
  824. X/*
  825. X * rewrite the newsrc file
  826. X */
  827. Xwritenewsrc(alist)
  828. Xactive *alist;
  829. X{
  830. X    register FILE *f;
  831. X    register active    *ap;
  832. X    register newsrc    *np;
  833. X    register int i;
  834. X    extern char **uflag;
  835. X    extern int usize;
  836. X
  837. X    if (!rc && !uflag && (!rcgrps || !*rcgrps))
  838. X        return;
  839. X
  840. X    signal(SIGINT, SIG_IGN);
  841. X    signal(SIGQUIT, SIG_IGN);
  842. X
  843. X    f = fopenf(rcname, "w");
  844. X    if (rcgrps && *rcgrps)
  845. X        (void) fprintf(f, "options -n %s\n", rcgrps);
  846. X    if (uflag) {
  847. X        scanhist(uflag, usize);        /* forget id's not in history */
  848. X        for (i = 0; i < usize; i++)    /* print whats left */
  849. X            if (uflag[i])
  850. X                (void) fprintf(f, "options -u %s\n", uflag[i]);
  851. X    }
  852. X    if (sortrc) {
  853. X        /*
  854. X         * sort newsrc so next time we use it,
  855. X         * history/newsrc comparisons will be faster
  856. X         */
  857. X        for (ap = alist; ap; ap = ap->a_next)
  858. X            if (np = findnewsrc(ap->a_name))
  859. X                writengline(f, np);
  860. X    } else
  861. X        for (np = rc; np; np = np->n_next)
  862. X            writengline(f, np);
  863. X    (void) fclose(f);
  864. X}
  865. X
  866. Xstatic
  867. Xwritengline(f, np)        /* write .newsrc n.g. line in normal form on f */
  868. Xregister newsrc *np;
  869. X{
  870. X    (void) fprintf(f, "%s%c 1-%d\n", np->n_name,
  871. X        (np->n_subscribe? ':': NEGCHAR), np->n_last);
  872. X}
  873. END_OF_FILE
  874. if test 6581 -ne `wc -c <'rna/newsrc.c'`; then
  875.     echo shar: \"'rna/newsrc.c'\" unpacked with wrong size!
  876. fi
  877. # end of 'rna/newsrc.c'
  878. fi
  879. if test -f 'rnews/fileart.c' -a "${1}" != "-c" ; then 
  880.   echo shar: Will not clobber existing file \"'rnews/fileart.c'\"
  881. else
  882. echo shar: Extracting \"'rnews/fileart.c'\" \(6901 characters\)
  883. sed "s/^X//" >'rnews/fileart.c' <<'END_OF_FILE'
  884. X/*
  885. X * fileart - file an article, given its temp file name and its headers
  886. X * TODO: change in junk policy, suggested by gnu (has this been done already?):
  887. X *    3 classes of ng: wanted, not wanted (!ng in sys -> ignore it),
  888. X *        don't know it (not in active -> change to junk).
  889. X * TODO: clean up packaging of fileart: push the 3-arg open caller into vers/*?
  890. X */
  891. X
  892. X#include <stdio.h>
  893. X#include <errno.h>
  894. X#include <sys/types.h>
  895. X
  896. X#include "fcntl.h"            /* try to define O_* and F_* */
  897. X
  898. X#include "news.h"
  899. X#include "newspaths.h"
  900. X#include "active.h"
  901. X#include "headers.h"
  902. X#include "system.h"
  903. X
  904. X#ifndef F_OK
  905. X#define F_OK 0
  906. X#endif
  907. X
  908. X#define JUNK "junk"            /* name of lost+found ng. */
  909. X#define CONTROL "control"
  910. X
  911. Xstatic long artnum;            /* asgnartnum sets artnum */
  912. Xstatic int goodngs;            /* asgnartnum reads goodngs */
  913. X
  914. Xstatic int debug = NO;
  915. X
  916. Xfiledebug(state)        /* set debugging state */
  917. Xint state;
  918. X{
  919. X    debug = state;
  920. X}
  921. X
  922. X/*
  923. X * TODO: new proposed junk policy:
  924. X * delay until the end, then file *once* in junk if any ngs
  925. X * were not in active but were in sys file subscription list.
  926. X */
  927. X/*
  928. X * File the article in "*tfp" in the spool directory.
  929. X * hdrs are the associated headers.  fileart fills in hdrs->h_files too.
  930. X *
  931. X * If openfirst is true, fill in h_tmpf with the name of the first link,
  932. X * fopen it (into *tfp), and make any remaining links.
  933. X * openfirst really means "Newsgroups:" has been seen.
  934. X * Generates Xref: header if needed.
  935. X */
  936. Xint
  937. Xfileart(hdrs, tfp, openfirst)
  938. Xregister struct headers *hdrs;
  939. XFILE **tfp;
  940. Xint openfirst;
  941. X{
  942. X    register char *comma;
  943. X    int status = ST_OKAY;
  944. X    char *ng;            /* point at current newsgroup */
  945. X    char artnumstr[MAXCOMP];    /* article number in ascii */
  946. X    char group[MAXFILE];        /* a group */
  947. X
  948. X    if (hdrs->h_filed)
  949. X        return status;
  950. X    artnum = 0;
  951. X    goodngs = 0;
  952. X    /*
  953. X     * Store in spooldir.
  954. X     * Link temp file to spooldir/ng/article-number for each ng.
  955. X     */
  956. X    for (ng = hdrs->h_ngs; ng != NULL; ng = comma) {
  957. X        int lstatus = ST_OKAY;
  958. X
  959. X        comma = index(ng, NGSEP);
  960. X        if (comma != NULL)
  961. X            *comma = '\0';        /* restored below */
  962. X        if (hdrs->h_ctlcmd != NULL)    /* ctl. msg.s go in CONTROL */
  963. X            (void) strcpy(group, CONTROL);
  964. X        else
  965. X            (void) strcpy(group, ng); /* copy out newsgroup name */
  966. X        if (comma != NULL)
  967. X            *comma++ = NGSEP;    /* step past comma */
  968. X
  969. X        lstatus |= asgnartnum(hdrs, tfp, openfirst, group, artnumstr);
  970. X        /*
  971. X         * No such group in active or link failed but our
  972. X         * subscription list permits this group,
  973. X         * so file it under "junk", if it exists.
  974. X         */
  975. X        if ((artnum < 1 || lstatus != ST_OKAY) &&
  976. X            ngmatch(oursys()->sy_ngs, group)) {
  977. X            (void) strcpy(group, JUNK);
  978. X            lstatus = asgnartnum(hdrs, tfp, openfirst,
  979. X                group, artnumstr);
  980. X            /*
  981. X             * You could set ST_DROPPED here if you think
  982. X             * one might accidentally not have "junk"
  983. X             * in active.  I tend to think the absence
  984. X             * of "junk" would be deliberate, to prevent
  985. X             * filing of junk articles.
  986. X             */
  987. X            if (artnum < 1 || lstatus != ST_OKAY)
  988. X                lstatus |= ST_NUKED;    /* no junk ng */
  989. X        }
  990. X        if (artnum >= 1 && lstatus == ST_OKAY) {
  991. X            /*
  992. X             * Article # was assigned and the link succeeded.
  993. X             * Update hdrs->h_files list for history.
  994. X             */
  995. X            hdrs->h_filed = YES;            /* make a note */
  996. X            if (hdrs->h_files[0] != '\0')
  997. X                (void) strcat(hdrs->h_files, " ");
  998. X            (void) strcat(hdrs->h_files, group);    /* normal case */
  999. X            (void) strcat(hdrs->h_files, SFNDELIM);
  1000. X            (void) strcat(hdrs->h_files, artnumstr);
  1001. X            ++goodngs;
  1002. X        }
  1003. X        status |= lstatus & ~ST_NUKED;
  1004. X    }
  1005. X    /*
  1006. X     * No good ngs if article was accepted by our subscription list,
  1007. X     * yet none of the groups are in our active file
  1008. X     * (e.g. net.rec.drugs,net.chew-the-fat) & no junk group exists.
  1009. X     *
  1010. X     * TODO: could call asgnartnum here instead.  Hmmm...
  1011. X     * Current policy makes a junk link for each bad group,
  1012. X     * this would instead make one junk link, no matter how
  1013. X     * many bad groups, and only if all are bad.
  1014. X     * But we want to know *why* there are no good ngs; it could
  1015. X     * be because they are all denied by our subscription list.
  1016. X     * Again, could set ST_DROPPED here (no junk group).
  1017. X     */
  1018. X    if (goodngs == 0)
  1019. X        status |= ST_NUKED;        /* TODO: complain: no good ngs? */
  1020. X    else if (goodngs > 1 && *tfp != NULL)    /* cross-posted? */
  1021. X        status |= emitxref(*tfp, hdrs);
  1022. X    return status;
  1023. X}
  1024. X
  1025. X/*
  1026. X * Assign a permanent name and article number to the temporary name hdrs->h_tmpf
  1027. X * in newsgroup "ng" & store the ascii form of the article number into "artnumstr",
  1028. X * returning the article number in "artnum".
  1029. X *
  1030. X * If openfirst is true and goodngs is zero, set inname to artname,
  1031. X * fopen artname and store the result through tfp.
  1032. X */
  1033. Xstatic int
  1034. Xasgnartnum(hdrs, tfp, openfirst, ng, artnumstr)
  1035. Xstruct headers *hdrs;
  1036. XFILE **tfp;
  1037. Xint openfirst;
  1038. Xchar *ng;
  1039. Xchar *artnumstr;
  1040. X{
  1041. X    register int status = ST_OKAY;
  1042. X    char *inname = hdrs->h_tmpf;
  1043. X    char slashng[MAXFILE];            /* a group, slashed */
  1044. X    extern int errno;
  1045. X
  1046. X#define openorlink(inname, artname, tfp, openfirst, goodngs) \
  1047. X    (openfirst && goodngs == 0? openlink(inname, artname, tfp): \
  1048. X    link(inname, artname) == 0)
  1049. X
  1050. X    (void) strcpy(slashng, ng);
  1051. X    mkfilenm(slashng);
  1052. X    while ((artnum = nxtartnum(ng)) >= 1) {
  1053. X        char artname[MAXFILE];        /* article file name */
  1054. X
  1055. X        (void) strcpy(artname, slashng);
  1056. X        (void) strcat(artname, SFNDELIM);
  1057. X        (void) sprintf(artnumstr, "%ld", artnum);
  1058. X        (void) strcat(artname, artnumstr);
  1059. X
  1060. X        /*
  1061. X         * we changed directory to spooldir in main(),
  1062. X         * so artname is relative to spooldir,
  1063. X         * therefore artname can be used as is.
  1064. X         */
  1065. X#ifdef notdef
  1066. X        (void) strcpy(artname, spoolfile(artname));
  1067. X#endif
  1068. X
  1069. X        if (debug && !(openfirst && goodngs == 0))
  1070. X            (void) fprintf(stderr, "about to link %s to %s... ",
  1071. X                inname, artname);
  1072. X        if (openorlink(inname, artname, tfp, openfirst, goodngs)) {
  1073. X            if (debug)
  1074. X                (void) fprintf(stderr, "success!\n");
  1075. X            break;        /* link succeeded */
  1076. X        } else {
  1077. X            /*
  1078. X             * Link failed.  Maybe some directories are missing,
  1079. X             * so create any missing directories and try again.
  1080. X             */
  1081. X            if (debug)
  1082. X                warning("failed!", "");
  1083. X            (void) checkdir(artname, getuid(), getgid());
  1084. X            if (openorlink(inname, artname, tfp, openfirst, goodngs))
  1085. X                break;        /* link succeeded this time */
  1086. X            else if (errno != EEXIST) {
  1087. X                warning("can't link to %s", artname);
  1088. X                status |= ST_DROPPED;
  1089. X                break;
  1090. X            }
  1091. X            /*
  1092. X             * Else artname exists.  It must be a numeric subgroup name,
  1093. X             * such as net.micro.432; try another article.
  1094. X             */
  1095. X        }
  1096. X    }
  1097. X    return status;
  1098. X}
  1099. X
  1100. X/*
  1101. X * Open artname, save the name on sp & the FILE pointer through tfp.
  1102. X */
  1103. Xstatic int
  1104. Xopenlink(sp, artname, tfp)
  1105. Xchar *sp;
  1106. Xchar *artname;
  1107. XFILE **tfp;
  1108. X{
  1109. X    (void) strcpy(sp, artname);    /* save a copy */
  1110. X#ifdef O_EXCL
  1111. X    /* This is the cheaper way. */
  1112. X    {
  1113. X    int fd = open(sp, O_WRONLY|O_CREAT|O_EXCL, 0666);
  1114. X
  1115. X    if (fd < 0)
  1116. X        *tfp = NULL;
  1117. X    else
  1118. X        *tfp = fdopen(fd, "w");
  1119. X    }
  1120. X#else
  1121. X    if (access(sp, F_OK) >= 0)    /* sp exists */
  1122. X        *tfp = NULL;        /* refuse to write on it */
  1123. X    else        
  1124. X        *tfp = fopen(sp, "w");    /* try to create it */
  1125. X#endif
  1126. X    return *tfp != NULL;
  1127. X}
  1128. END_OF_FILE
  1129. if test 6901 -ne `wc -c <'rnews/fileart.c'`; then
  1130.     echo shar: \"'rnews/fileart.c'\" unpacked with wrong size!
  1131. fi
  1132. # end of 'rnews/fileart.c'
  1133. fi
  1134. if test -f 'rnews/procart.c' -a "${1}" != "-c" ; then 
  1135.   echo shar: Will not clobber existing file \"'rnews/procart.c'\"
  1136. else
  1137. echo shar: Extracting \"'rnews/procart.c'\" \(7574 characters\)
  1138. sed "s/^X//" >'rnews/procart.c' <<'END_OF_FILE'
  1139. X/*
  1140. X * process a single incoming article
  1141. X */
  1142. X
  1143. X#include <stdio.h>
  1144. X#include <sys/types.h>
  1145. X#include "news.h"
  1146. X#include "active.h"
  1147. X#include "headers.h"
  1148. X#include "system.h"
  1149. X
  1150. X#ifndef COPYSIZE
  1151. X#ifdef pdp11
  1152. X#define COPYSIZE BUFSIZ
  1153. X#else
  1154. X#define COPYSIZE 8192
  1155. X#endif                /* pdp11 */
  1156. X#endif                /* COPYSIZE */
  1157. X
  1158. Xextern char *exclude;        /* for erik */
  1159. X
  1160. X/*
  1161. X * Copy the article on "in" to a temporary name in the news spool directory,
  1162. X * unlink temp name; *or* copy into the final names, if known earlier enough.
  1163. X * (Sets h_tmpf in or near mungehdrs() or hdrdump().)
  1164. X * If the spool file opened, install the article it contains.
  1165. X */
  1166. Xint
  1167. Xcpinsart(in, inname, maxima)
  1168. XFILE *in;
  1169. Xchar *inname;
  1170. Xlong maxima;
  1171. X{
  1172. X    int status = ST_OKAY;
  1173. X    FILE *tf = NULL;
  1174. X    struct headers hdrs;
  1175. X
  1176. X    hdrinit(&hdrs);
  1177. X    status |= copyart(in, inname, maxima, &tf, &hdrs);
  1178. X    if (status&ST_NUKED) {            /* no good ngs (in fileart) */
  1179. X        char *msgid = "", *ngs = "";
  1180. X
  1181. X        status &= ~ST_NUKED;        /* nuking isn't serious */
  1182. X        if (hdrs.h_msgid != NULL)
  1183. X            msgid = hdrs.h_msgid;    /* caution */
  1184. X        if (hdrs.h_ngs != NULL)
  1185. X            ngs = hdrs.h_ngs;    /* caution */
  1186. X        timestamp(stdout, (time_t *)NULL, (char **)NULL);
  1187. X        (void) printf(" refused %s bad groups in `%s' and no junk group\n",
  1188. X            msgid, ngs);
  1189. X    } else if (tf == NULL) {
  1190. X        warning("can't open spool file `%s'", hdrs.h_tmpf);
  1191. X        status |= ST_DROPPED;
  1192. X    } else {
  1193. X        status |= insart(tf, &hdrs);
  1194. X        (void) fclose(tf);
  1195. X    }
  1196. X    freeheaders(&hdrs);
  1197. X    return status;
  1198. X}
  1199. X
  1200. X/*
  1201. X * Copy the next charcnt bytes of "in" (may be not a disk file)
  1202. X * to a permanent file under a (possibly) temporary name.
  1203. X * Must munge certain headers on the way & remember certain values.
  1204. X * mungehdrs() or hdrdump() sets hdrs->h_tmpf & *tfp.
  1205. X */
  1206. X/* ARGSUSED inname */
  1207. Xstatic int
  1208. Xcopyart(in, inname, charcnt, tfp, hdrs)
  1209. Xregister FILE *in;
  1210. Xchar *inname;
  1211. Xregister long charcnt;
  1212. Xregister FILE **tfp;
  1213. Xstruct headers *hdrs;
  1214. X{
  1215. X    register int readcnt;
  1216. X    int status = ST_OKAY;
  1217. X    char *s = NULL;
  1218. X    char line[COPYSIZE];
  1219. X
  1220. X    hdrwretch();                /* reset the header parser */
  1221. X    /*
  1222. X     * people think this loop is ugly; not sure why.
  1223. X     * if the byte count is positive, read a line; if it doesn't return
  1224. X     * EOF and is a header, then adjust byte count, eat and munge headers.
  1225. X     * strlen(line) must be computed before hdrmutate is called, as it
  1226. X     * removes newlines.
  1227. X     */
  1228. X    while (charcnt > 0 &&
  1229. X        (s = fgets(line, (int)min(sizeof line-1, charcnt)+1, in)) != NULL
  1230. X        && ishdr(line)) {
  1231. X            charcnt -= strlen(line);
  1232. X        status |= hdrmutate(hdrs, line, tfp);    /* eat & munge headers */
  1233. X            /* hdrdump() counts hdrs->h_charswritten */
  1234. X    }
  1235. X    hdrdeflt(hdrs);
  1236. X
  1237. X    /* write any saved headers, trigger fileart */
  1238. X    status |= hdrdump(tfp, hdrs, YES);
  1239. X
  1240. X    /* Copy first body line. */
  1241. X    if (charcnt > 0 && s != NULL) {    /* fgets worked: not a header line */
  1242. X        register int linelen = strlen(line);
  1243. X
  1244. X        if (*tfp != NULL && fputs(line, *tfp) == EOF)
  1245. X            status = fulldisk(status|ST_DROPPED,
  1246. X                (hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
  1247. X        charcnt -= linelen;    
  1248. X        hdrs->h_charswritten += linelen;
  1249. X    }
  1250. X    /*
  1251. X     * Copy at most "sizeof line" bytes at a time
  1252. X     * and exactly charcnt bytes in total, barring EOF.
  1253. X     */
  1254. X    for (; charcnt > 0 && !(status&ST_DISKFULL) &&
  1255. X        (readcnt=fread(line, 1, (int)min(charcnt, sizeof line), in)) > 0;
  1256. X        charcnt -= readcnt, hdrs->h_charswritten += readcnt)
  1257. X        if (*tfp != NULL && fwrite(line, 1, readcnt, *tfp) != readcnt)
  1258. X            status = fulldisk(status|ST_DROPPED,
  1259. X                (hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
  1260. X    if (*tfp != NULL && fflush(*tfp) == EOF)    /* force to disk */
  1261. X        status = fulldisk(status|ST_DROPPED,
  1262. X            (hdrs->h_unlink? hdrs->h_tmpf: hdrs->h_files));
  1263. X    if (charcnt > 0 && remote) {    /* TODO: don't use "remote" */
  1264. X        (void) fprintf(stderr, "%s: article %s short by %ld bytes\n",
  1265. X            progname, (hdrs->h_msgid != NULL? hdrs->h_msgid: ""),
  1266. X            (long)charcnt);
  1267. X        status |= ST_SHORT;    /* N.B.: do not uninstall this article */
  1268. X    }
  1269. X    return status;
  1270. X}
  1271. X
  1272. X/*
  1273. X * Read headers from "in".
  1274. X * Iff we haven't seen this article already and we like the groups,
  1275. X * install the article on "in" & hdrs->h_tmpf.
  1276. X * Rename hdrs->h_tmpf into the news spool directory.
  1277. X * Add history entries for the article.
  1278. X * Transmit the article, like a dose of clap, to our neighbours.
  1279. X * Process control mess(age)es.
  1280. X * Unlink hdrs->h_tmpf, if a temporary link.
  1281. X */
  1282. Xstatic int
  1283. Xinsart(in, hdrs)
  1284. XFILE *in;
  1285. Xstruct headers *hdrs;
  1286. X{
  1287. X    register int status = ST_OKAY;
  1288. X
  1289. X    status |= reject(hdrs);
  1290. X    if (status&(ST_DROPPED|ST_NUKED))
  1291. X        uninsart(hdrs);    /* remove existing links; give back assigned #s */
  1292. X    else {
  1293. X        /*
  1294. X         * Ordinary filing: if not already filed,
  1295. X         * make links to hdrs->h_tmpf (which will exist).
  1296. X         */
  1297. X        status |= fileart(hdrs, &in, 0);    /* generates Xref: */
  1298. X        if (!(status&(ST_DROPPED|ST_NUKED))) {
  1299. X            status |= history(hdrs);    /* writes "received: " */
  1300. X            /* writes systems on stdout */
  1301. X            status |= transmit(hdrs, remote, exclude);
  1302. X            (void) putc('\n', stdout);    /* ends the line */
  1303. X            (void) fflush(stdout);        /* crash-proofness */
  1304. X            if (hdrs->h_ctlcmd != NULL)
  1305. X                status |= ctlmsg(hdrs);
  1306. X        }
  1307. X    }
  1308. X        status &= ~ST_NUKED;            /* nuking is quite casual */
  1309. X    if (hdrs->h_unlink && unlink(hdrs->h_tmpf) < 0) {
  1310. X        warning("can't unlink `%s'", hdrs->h_tmpf);
  1311. X        status |= ST_ACCESS;
  1312. X    }
  1313. X    return status;
  1314. X}
  1315. X
  1316. X/*
  1317. X * Reject articles.  This can be arbitrarily picky.
  1318. X */
  1319. Xint
  1320. Xreject(hdrs)
  1321. Xregister struct headers *hdrs;
  1322. X{
  1323. X    if (alreadyseen(hdrs->h_msgid)) {
  1324. X        timestamp(stdout, (time_t *)NULL, (char **)NULL);
  1325. X        (void) printf(" refused %s duplicate\n", hdrs->h_msgid);
  1326. X    } else if (!ngmatch(oursys()->sy_ngs, hdrs->h_ngs)) {
  1327. X        timestamp(stdout, (time_t *)NULL, (char **)NULL);
  1328. X        (void) printf(" refused %s bad groups in %s\n",
  1329. X            hdrs->h_msgid, hdrs->h_ngs);
  1330. X    } else if (moderated(hdrs) && hdrs->h_approved == NULL) {
  1331. X        timestamp(stdout, (time_t *)NULL, (char **)NULL);
  1332. X        (void) printf(" refused %s unapproved article in moderated group(s) %s\n",
  1333. X            hdrs->h_msgid, hdrs->h_ngs);
  1334. X    } else
  1335. X        return ST_OKAY;
  1336. X    if (remote)        /* TODO: test this some other way */
  1337. X        return ST_NUKED;
  1338. X    else
  1339. X        return ST_NUKED|ST_DROPPED;    /* more serious if local */
  1340. X}
  1341. X
  1342. X/*
  1343. X * Remove hdrs->h_files (permanent names) and h_tmpf (temporary names),
  1344. X * and return assigned article numbers.
  1345. X */
  1346. Xuninsart(hdrs)
  1347. Xregister struct headers *hdrs;
  1348. X{
  1349. X    if (hdrs->h_unlink && hdrs->h_tmpf[0] != '\0') {    /* temp name */
  1350. X        (void) unlink(hdrs->h_tmpf);    /* I don't wanna know... */
  1351. X        hdrs->h_unlink = NO;
  1352. X    }
  1353. X    (void) snuffmayreturn(hdrs->h_files, YES);
  1354. X}
  1355. X
  1356. Xint
  1357. Xsnufffiles(filelist)        /* just unlink all files in filelist */
  1358. Xchar *filelist;
  1359. X{
  1360. X    return snuffmayreturn(filelist, NO);
  1361. X}
  1362. X
  1363. Xint
  1364. Xsnuffmayreturn(filelist, artret)    /* unlink all files in filelist (return artids?) */
  1365. Xchar *filelist;
  1366. Xint artret;
  1367. X{
  1368. X    register char *arts, *spacep, *slashp;
  1369. X    int status = ST_OKAY;
  1370. X    char artnm[MAXFILE];
  1371. X
  1372. X    /* this is a deadly tedious job and I really should automate it */
  1373. X    for (arts = filelist; arts != NULL && arts[0] != '\0';
  1374. X         arts = (spacep == NULL? NULL: spacep+1)) {
  1375. X        spacep = index(arts, ' ');
  1376. X        if (spacep != NULL)
  1377. X            spacep[0] = '\0';    /* will be restored below */
  1378. X             (void) strcpy(artnm, arts);
  1379. X             if (spacep != NULL)
  1380. X                 spacep[0] = ' ';    /* restore space */
  1381. X
  1382. X             slashp = index(artnm, FNDELIM);
  1383. X             if (slashp != NULL)
  1384. X                 slashp[0] = '\0';    /* will be restored below */
  1385. X             if (artret)
  1386. X            (void) prevartnum(artnm);    /* return assigned # */
  1387. X             if (slashp != NULL)
  1388. X                 slashp[0] = FNDELIM;    /* restore slash */
  1389. X
  1390. X             mkfilenm(artnm);
  1391. X        if (unlink(artnm) < 0) {    /* remove a link & hope */
  1392. X            (void) fprintf(stderr, "%s: can't unlink %s\n",
  1393. X                progname, artnm);
  1394. X                 status |= ST_ACCESS;
  1395. X        }
  1396. X    }
  1397. X    return status;
  1398. X}
  1399. END_OF_FILE
  1400. if test 7574 -ne `wc -c <'rnews/procart.c'`; then
  1401.     echo shar: \"'rnews/procart.c'\" unpacked with wrong size!
  1402. fi
  1403. # end of 'rnews/procart.c'
  1404. fi
  1405. if test -f 'rnews/sys.c' -a "${1}" != "-c" ; then 
  1406.   echo shar: Will not clobber existing file \"'rnews/sys.c'\"
  1407. else
  1408. echo shar: Extracting \"'rnews/sys.c'\" \(6730 characters\)
  1409. sed "s/^X//" >'rnews/sys.c' <<'END_OF_FILE'
  1410. X/*
  1411. X * news sys file reading functions (in-memory version)
  1412. X */
  1413. X
  1414. X#include <stdio.h>
  1415. X#include <ctype.h>
  1416. X#include <sys/types.h>
  1417. X#include <sys/stat.h>
  1418. X#include "news.h"
  1419. X#include "newspaths.h"
  1420. X#include "system.h"
  1421. X
  1422. Xstatic FILE *fp = NULL;        /* descriptor for libfile("sys") */
  1423. Xstatic char filerelname[] = "sys";
  1424. X
  1425. Xstatic struct system *firstsys = NULL;    /* cache */
  1426. Xstatic struct system *currsys = NULL;    /* current system */
  1427. X
  1428. X/* forward decls */
  1429. Xchar *parsecolon();
  1430. X
  1431. Xstruct system *
  1432. Xoursys()            /* return our sys entry */
  1433. X{
  1434. X    register struct system *sys;
  1435. X    static struct system fakesys;
  1436. X    static struct system *thissys = NULL;
  1437. X
  1438. X    if (thissys != NULL)        /* in-core-only optimisation */
  1439. X        return thissys;
  1440. X    rewsys();
  1441. X    while ((sys = nextsys()) != NULL && !STREQ(sys->sy_name, hostname()))
  1442. X        ;
  1443. X    if (sys == NULL) {        /* no entry; cook one up */
  1444. X        /* TODO: test this by some other means instead */
  1445. X        if (!remote)        /* no -p, local posting */
  1446. X            (void) fprintf(stderr,
  1447. X        "%s: no %s file - your news will not leave this machine\n",
  1448. X                progname, libfile(filerelname));
  1449. X        fakesys.sy_name = hostname();
  1450. X        fakesys.sy_ngs = "all";
  1451. X        fakesys.sy_flags = 0;
  1452. X        fakesys.sy_lochops = 0;
  1453. X        fakesys.sy_cmd = "";
  1454. X        fakesys.sy_next = NULL;
  1455. X        sys = &fakesys;
  1456. X    }
  1457. X    thissys = sys;            /* for future reference */
  1458. X    return sys;
  1459. X}
  1460. X
  1461. X/*
  1462. X * Returned pointer points at a static struct whose members
  1463. X * point at static storage.
  1464. X */
  1465. Xstruct system *
  1466. Xnextsys()                /* return next sys entry */
  1467. X{
  1468. X    struct system *retsys;
  1469. X
  1470. X    if (firstsys == NULL && fp == NULL)
  1471. X        if ((fp = fopenwclex(libfile(filerelname), "r")) == NULL)
  1472. X            return NULL;
  1473. X    if (fp != NULL && firstsys == NULL)    /* file open, no cache */
  1474. X        readsys();            /* read & parse fp */
  1475. X    retsys = currsys;            /* save current ptr. */
  1476. X    if (currsys != NULL)
  1477. X        currsys = currsys->sy_next;    /* advance current ptr. */
  1478. X    return retsys;
  1479. X}
  1480. X
  1481. Xrewsys()
  1482. X{
  1483. X    currsys = firstsys;
  1484. X}
  1485. X
  1486. Xstatic char *curr, *next;            /* parsing state */
  1487. X
  1488. XSTATIC
  1489. Xreadsys()
  1490. X{
  1491. X    register char *sysline;
  1492. X
  1493. X    rewind(fp);
  1494. X    /* read possibly continued lines of arbitrary length */
  1495. X    while ((sysline = cfgetms(fp)) != NULL) {
  1496. X        if (sysline[0] != '#' && sysline[0] != '\n') {    /* not a comment */
  1497. X            register struct system *sysp;
  1498. X            register char *slashp;
  1499. X            char *flagstring;
  1500. X
  1501. X            /* This storage is never freed. */
  1502. X            sysp = (struct system *) malloc(sizeof *sysp);
  1503. X            if (sysp == NULL)
  1504. X                errunlock("out of memory for system structs", "");
  1505. X
  1506. X            /* parse into sysp */
  1507. X            trim(sysline);
  1508. X            next = sysline;
  1509. X            parse(&sysp->sy_name);
  1510. X            parse(&sysp->sy_ngs);
  1511. X            parse(&flagstring);
  1512. X            parse(&sysp->sy_cmd);
  1513. X            /* could check for extra fields here */
  1514. X
  1515. X            parseflags(flagstring, sysp);
  1516. X            free(flagstring);        /* malloced by parse */
  1517. X            sysp->sy_next = NULL;
  1518. X
  1519. X            /* reparse for embedded slashes */
  1520. X            slashp = index(sysp->sy_name, '/');
  1521. X            if (slashp != NULL) {        /* parse name/excl1,excl2,... */
  1522. X                *slashp = '\0';        /* terminate name */
  1523. X                sysp->sy_excl = slashp + 1;
  1524. X            } else
  1525. X                sysp->sy_excl = NULL;    /* no exclusions */
  1526. X            slashp = index(sysp->sy_ngs, '/');
  1527. X            if (slashp != NULL) {        /* parse ngs/distrs */
  1528. X                *slashp = '\0';        /* terminate ngs */
  1529. X                sysp->sy_distr = slashp + 1;
  1530. X            } else
  1531. X                sysp->sy_distr = sysp->sy_ngs;
  1532. X
  1533. X            /* expand ME if any */
  1534. X            if (STREQ(sysp->sy_name, "ME")) {
  1535. X                free(sysp->sy_name);    /* malloced by parse */
  1536. X                sysp->sy_name = hostname();    /* NB not malloced */
  1537. X            }
  1538. X
  1539. X            /* fill in any defaults */
  1540. X
  1541. X            /*
  1542. X             * If no batch file name was given, use the default
  1543. X             * ($NEWSCTL/batch/b.system/togo).
  1544. X             */ 
  1545. X            if (sysp->sy_flags&FLG_BATCH && sysp->sy_cmd[0] == '\0') {
  1546. X                char *deffile = emalloc((unsigned)STRLEN("batch/b.") +
  1547. X                    strlen(sysp->sy_name) + STRLEN("/togo") + 1);
  1548. X
  1549. X                (void) strcpy(deffile, "batch/b.");
  1550. X                (void) strcat(deffile, sysp->sy_name);
  1551. X                (void) strcat(deffile, "/togo");
  1552. X                free(sysp->sy_cmd);    /* malloced by parse */
  1553. X                sysp->sy_cmd = libfile(deffile); /* NB not malloced */
  1554. X                free(deffile);
  1555. X            }
  1556. X            /*
  1557. X             * If no command was given, use the default
  1558. X             * (uux - -r -z system!rnews).
  1559. X             * (This *is* yucky and uucp-version-dependent.)
  1560. X             */ 
  1561. X            if (!(sysp->sy_flags&FLG_BATCH) && sysp->sy_cmd[0] == '\0') {
  1562. X                /* TODO: send mail to usenet, harassing him. */
  1563. X                /* TODO: search PATH including $NEWSCTL/syscmd */
  1564. X                free(sysp->sy_cmd);    /* malloced by parse */
  1565. X                sysp->sy_cmd = emalloc((unsigned)STRLEN("uux - -r -z ") +
  1566. X                    strlen(sysp->sy_name) + STRLEN("!rnews") + 1);
  1567. X                (void) strcpy(sysp->sy_cmd, "uux - -r -z ");
  1568. X                (void) strcat(sysp->sy_cmd, sysp->sy_name);
  1569. X                (void) strcat(sysp->sy_cmd, "!rnews");
  1570. X            }
  1571. X
  1572. X            /* stash *sysp away on the tail of the current list */
  1573. X            if (firstsys == NULL)
  1574. X                firstsys = sysp;        /* 1st system */
  1575. X            else
  1576. X                currsys->sy_next = sysp;    /* tack on tail */
  1577. X            currsys = sysp;
  1578. X        }
  1579. X        free(sysline);
  1580. X    }
  1581. X    (void) fclose(fp);        /* file no longer needed */
  1582. X    fp = NULL;            /* mark file closed */
  1583. X    rewsys();
  1584. X}
  1585. X
  1586. XSTATIC
  1587. Xparse(into)
  1588. Xregister char **into;
  1589. X{
  1590. X    curr = next;
  1591. X    if (curr == NULL)
  1592. X        *into = strsave("");
  1593. X    else {
  1594. X        next = parsecolon(curr);
  1595. X        *into = strsave(curr);
  1596. X    }
  1597. X    /* *into is never freed. */
  1598. X    if (*into == NULL)
  1599. X        errunlock("out of memory for sys strings", "");
  1600. X}
  1601. X
  1602. XSTATIC char *
  1603. Xparsecolon(line)        /* return NULL or ptr. to byte after colon */
  1604. Xchar *line;
  1605. X{
  1606. X    register char *colon;
  1607. X
  1608. X    INDEX(line, ':', colon);
  1609. X    if (colon != NULL)
  1610. X        *colon++ = '\0';    /* turn colon into a NUL */
  1611. X    return colon;
  1612. X}
  1613. X
  1614. XSTATIC
  1615. Xparseflags(flags, sysp)
  1616. Xregister char *flags;            /* flags string */
  1617. Xregister struct system *sysp;        /* result here */
  1618. X{
  1619. X    sysp->sy_flags = 0;
  1620. X    sysp->sy_lochops = 0;        /* default L value */
  1621. X    for (; *flags != '\0'; flags++)
  1622. X        switch (*flags) {
  1623. X        case 'A':
  1624. X            errunlock("A news format not supported", "");
  1625. X            /* NOTREACHED */
  1626. X        case 'B':                /* mostly harmless */
  1627. X            break;
  1628. X        case 'f':
  1629. X            sysp->sy_flags |= FLG_SZBATCH;
  1630. X            break;
  1631. X        case 'F':
  1632. X            sysp->sy_flags |= FLG_BATCH;
  1633. X            break;
  1634. X        case 'I':                /* NNTP */
  1635. X            /* TODO: I sys flag: I-have, write msg-ids */
  1636. X            break;
  1637. X        case 'L':                /* Ln */
  1638. X            sysp->sy_flags |= FLG_LOCAL;
  1639. X            sysp->sy_lochops = 0;
  1640. X            if (isascii(flags[1]) && isdigit(flags[1])) {
  1641. X                sysp->sy_lochops *= 10;
  1642. X                sysp->sy_lochops += *++flags - '0';
  1643. X            }
  1644. X            break;
  1645. X        case 'm':
  1646. X            /* TODO: m sys flag: send only moderated groups */
  1647. X            break;
  1648. X        case 'N':
  1649. X            sysp->sy_flags |= FLG_IHAVE;
  1650. X            errunlock("N flag given but I-have/send-me is not supported", "");
  1651. X            /* NOTREACHED */
  1652. X        case 'u':
  1653. X            /* TODO: u sys flag: send only unmoderated groups */
  1654. X            break;
  1655. X        case 'U':            /* mostly harmless */
  1656. X            /* sysp->sy_flags |= FLG_PERM; */
  1657. X            break;
  1658. X        case 'H':            /* bugger off */
  1659. X        case 'S':            /* bugger off */
  1660. X        case 'M':            /* multicast: obs., see batcher */
  1661. X        case 'O':            /* multicast: obs., see batcher */
  1662. X        default:
  1663. X            errunlock("unknown sys flag `%c' given", *flags);
  1664. X            /* NOTREACHED */
  1665. X        }
  1666. X}
  1667. END_OF_FILE
  1668. if test 6730 -ne `wc -c <'rnews/sys.c'`; then
  1669.     echo shar: \"'rnews/sys.c'\" unpacked with wrong size!
  1670. fi
  1671. # end of 'rnews/sys.c'
  1672. fi
  1673. echo shar: End of archive 9 \(of 14\).
  1674. ##  End of shell archive.
  1675. exit 0
  1676.